
#pragma once
#include <compl.h>
/* 同步等待策略，考虑以下方式 */
/* 普通自旋 */
/* 出让CPU(线程) - 不会失败 */
/* 出让CPU(协程) - 不会失败*/
/* 调度耦合的等待如futex, barrier wait等 - 不会失败(这种可以通过宏来增加)*/
/* 定时等待, 超时返回失败, 定时等待策略需要显示传入一个时钟tls变量 */

/* waitcnt等于0也是失败 */
/* wait */
/* 第一个参数hword_t cnt用于sched_yield */
/* 还需要yieldto其他协程 */
/* 兼容futex机制, 能不能兼容其他? 如信号量等 */
STA_OUFUN(blkwait)
waitcnt_t (* const waitf) (void *wptr, void *pwait_ifeq_to, waitcnt_t cnt);
void (* const wakef) (void *wptr, void *pnotify_newval);
END_OUFUN(blkwait)

/* 自旋等待, 不使用任何机制 */
SAI waitcnt_t waitf_spin(void *wptr, void *pwait_ifeq_to, waitcnt_t cnt){
	PARAM_USED(wptr, pwait_ifeq_to);
	PAUSE(); /* FIXME: 看是不是等待策略的问题 */
	/* sched_yield(); */
	return cnt;
}
SAI void wakef_spin(void *wptr, void *pnotify_newval){
	PARAM_USED(wptr, pnotify_newval);
}

NEW_OUFUN(blkwait, spin_wait, waitf_spin, wakef_spin)


/* 有限spin */
SAI waitcnt_t waitf_spinbounded(void *wptr, void *pwait_ifeq_to, waitcnt_t cnt){
	PARAM_USED(wptr, pwait_ifeq_to);
	PAUSE();
	return cnt - 1;
}

NEW_OUFUN(blkwait, spin_wait_bounded, waitf_spinbounded, wakef_spin)
/* 填入依赖定义定时等待 */
#define DEF_WAITF_TIME(ptls_timestamp, get_timestamp)				\
SAI waitcnt_t waitf_timedout(void *wptr, void *pwait_ifeq_to, waitcnt_t cnt){\
	PARAM_USED(wptr, pwait_ifeq_to);\
	waitcnt_t timestamp = get_timestamp();\
	waitcnt_t diff = get_timestamp() - (*(ptls_timestamp));\
	*(ptls_timestamp) = timestamp;\
	if (diff >= cnt) return 0;\
	else return cnt - diff;\
}\
SAI void wakef_timedout(void *wptr, void *pnotify_newval){\
	PARAM_USED(wptr, pnotify_newval);\
}\
NEW_OUFUN(blkwait, timeout_wait, waitf_timedout, wakef_timedout)

/* 出让cpu */
#ifdef __unix__
	#include <pthread.h>
	SAI waitcnt_t waitf_schedyield(void *wptr, void *pwait_ifeq_to, waitcnt_t cnt){
		PARAM_USED(wptr, pwait_ifeq_to);
		sched_yield();
		return cnt;
	}
	SAI void wakef_schedyield(void *pfutex, void *pnotify_newval){
		PARAM_USED(pfutex, pnotify_newval);
	}
	NEW_OUFUN(blkwait, schedyield_wait, waitf_schedyield, wakef_schedyield)
#endif

/* 如果和一个futex组合呢? */
#ifdef __linux__
#include <unix/ddblk/futex.h>
SAI waitcnt_t waitf_futex(void *wptr, void *pwait_ifeq_to, waitcnt_t cnt){
	futex((int *)wptr, FUTEX_WAIT_PRIVATE, *(uint32_t *)pwait_ifeq_to, NULL, NULL, 0);
	return cnt;
}
SAI void wakef_futex(void *wptr, void *pnotify_newval){
	/* 唤醒1个新线程 */
	PARAM_USED(pnotify_newval);
	futex((int *)wptr, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
}
NEW_OUFUN(blkwait, futex_wait, waitf_futex, wakef_futex)
#endif

